package thoven.achievement.net.jsonutil.service

import com.google.gson.JsonArray
import com.google.gson.JsonElement
import com.google.gson.JsonObject
import com.google.gson.JsonParser

/**
 * JSON 转 Java 实体类转换器
 */
object JsonToJavaConverter {
    
    /**
     * 将 JSON 转换为 Java 实体类
     */
    fun convert(json: String, className: String = "JsonEntity", useSerializable: Boolean = true): Result<String> {
        return try {
            val jsonElement = JsonParser.parseString(json)
            
            if (!jsonElement.isJsonObject) {
                return Result.failure(IllegalArgumentException("JSON must be an object"))
            }
            
            val classes = mutableListOf<String>()
            val mainClass = generateClass(jsonElement.asJsonObject, className, useSerializable, classes)
            
            // 组合所有类
            val result = buildString {
                appendLine("// Generated from JSON")
                appendLine()
                appendLine(mainClass)
                
                if (classes.isNotEmpty()) {
                    appendLine()
                    classes.forEach {
                        appendLine(it)
                        appendLine()
                    }
                }
            }
            
            Result.success(result)
        } catch (e: Exception) {
            Result.failure(e)
        }
    }
    
    /**
     * 生成 Java 类
     */
    private fun generateClass(
        jsonObject: JsonObject,
        className: String,
        useSerializable: Boolean,
        innerClasses: MutableList<String>
    ): String {
        val fields = mutableListOf<String>()
        val nestedClassNames = mutableSetOf<String>()
        
        jsonObject.entrySet().forEach { (key, value) ->
            val fieldName = sanitizeFieldName(key)
            val (fieldType, nestedClass) = getFieldType(value, capitalizeFirst(fieldName), innerClasses)
            
            fields.add("    private $fieldType $fieldName;")
            
            if (nestedClass != null) {
                nestedClassNames.add(nestedClass)
            }
        }
        
        return buildString {
            if (useSerializable) {
                appendLine("import java.io.Serializable;")
                appendLine()
            }
            
            append("public class $className")
            if (useSerializable) {
                append(" implements Serializable")
            }
            appendLine(" {")
            
            if (useSerializable) {
                appendLine("    private static final long serialVersionUID = 1L;")
                appendLine()
            }
            
            // 字段
            fields.forEach { appendLine(it) }
            appendLine()
            
            // Getter 和 Setter
            jsonObject.entrySet().forEach { (key, value) ->
                val fieldName = sanitizeFieldName(key)
                val (fieldType, _) = getFieldType(value, capitalizeFirst(fieldName), innerClasses)
                
                // Getter
                appendLine("    public $fieldType get${capitalizeFirst(fieldName)}() {")
                appendLine("        return $fieldName;")
                appendLine("    }")
                appendLine()
                
                // Setter
                appendLine("    public void set${capitalizeFirst(fieldName)}($fieldType $fieldName) {")
                appendLine("        this.$fieldName = $fieldName;")
                appendLine("    }")
                appendLine()
            }
            
            append("}")
        }
    }
    
    /**
     * 获取字段类型
     */
    private fun getFieldType(
        element: JsonElement,
        suggestedClassName: String,
        innerClasses: MutableList<String>
    ): Pair<String, String?> {
        return when {
            element.isJsonPrimitive -> {
                val primitive = element.asJsonPrimitive
                val type = when {
                    primitive.isBoolean -> "Boolean"
                    primitive.isNumber -> {
                        val num = primitive.asNumber
                        when {
                            num.toString().contains(".") -> "Double"
                            num.toLong() > Int.MAX_VALUE || num.toLong() < Int.MIN_VALUE -> "Long"
                            else -> "Integer"
                        }
                    }
                    else -> "String"
                }
                Pair(type, null)
            }
            element.isJsonObject -> {
                val nestedClass = generateClass(element.asJsonObject, suggestedClassName, true, innerClasses)
                innerClasses.add(nestedClass)
                Pair(suggestedClassName, suggestedClassName)
            }
            element.isJsonArray -> {
                val array = element.asJsonArray
                if (array.size() == 0) {
                    Pair("List<Object>", null)
                } else {
                    val firstElement = array[0]
                    val (itemType, nestedClassName) = getFieldType(firstElement, suggestedClassName + "Item", innerClasses)
                    Pair("List<$itemType>", nestedClassName)
                }
            }
            element.isJsonNull -> {
                Pair("Object", null)
            }
            else -> {
                Pair("Object", null)
            }
        }
    }
    
    /**
     * 清理字段名
     */
    private fun sanitizeFieldName(name: String): String {
        var result = name.replace(Regex("[^a-zA-Z0-9_]"), "_")
        
        // 如果以数字开头，添加下划线
        if (result.isNotEmpty() && result[0].isDigit()) {
            result = "_$result"
        }
        
        // 如果是 Java 关键字，添加下划线
        if (isJavaKeyword(result)) {
            result = "_$result"
        }
        
        return result
    }
    
    /**
     * 首字母大写
     */
    private fun capitalizeFirst(str: String): String {
        return if (str.isEmpty()) str else str[0].uppercase() + str.substring(1)
    }
    
    /**
     * 检查是否是 Java 关键字
     */
    private fun isJavaKeyword(word: String): Boolean {
        val keywords = setOf(
            "abstract", "assert", "boolean", "break", "byte", "case", "catch", "char",
            "class", "const", "continue", "default", "do", "double", "else", "enum",
            "extends", "final", "finally", "float", "for", "goto", "if", "implements",
            "import", "instanceof", "int", "interface", "long", "native", "new", "package",
            "private", "protected", "public", "return", "short", "static", "strictfp",
            "super", "switch", "synchronized", "this", "throw", "throws", "transient",
            "try", "void", "volatile", "while"
        )
        return keywords.contains(word)
    }
}

